package rt2

import (
	"errors"
	"fmt"

	"gitee.com/zhang-li17/rt2/pcol"

	"gitee.com/copperxcx/res"
)

func registerDecodeResTypeWithFunc[T res.ScalarType](c *ClientHandler, t pcol.ResourceType, fget getResFunc[T], fset setResFunc[T]) error {
	dec := getTypeResDecoder[T](c, fget, fset)

	err := c.registerDecodeResType(t, dec)
	if err == nil {
		c.resTypeFuncMap[t] = resTypeDecoderFunc[T]{t, fset, fget}
	}
	return err
}
func (c *ClientHandler) registerDecodeResType(t pcol.ResourceType, d TypeResDecoder) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	_, ok := c.resDecoder[t]
	if ok {

		return errors.New("resource type already registered")
	} else {

	}

	c.resDecoder[t] = d

	return nil
}

func getTypeResDecoder[T res.ScalarType](c *ClientHandler, fget func(*pcol.Res) T, fset func(*pcol.Res, T)) TypeResDecoder {
	return func(mgr *res.ResManager, r *pcol.Res) error {
		val := fget(r)
		if r.GetWritable() {
			scalar := res.GetWritableScalar[T](mgr, r.GetName())
			if scalar != nil {
				s, _ := scalar.(res.IWritableScalarHelper[T])
				s.UpdateValue(val)
				c.resMap[r.GetName()].Reset()
				c.resMap[r.GetName()] = r
				return nil
			}
			if res, ok := c.resMap[r.GetName()]; ok {
				return fmt.Errorf("recv resource changed: %v - > %v", res, r)
			}
			s := res.NewWritableScalar(r.GetName(), r.Description, val)
			// 设置值，发送设置指令
			s.SetWriteCallback(func(self res.IWritableScalar[T], val T) error {
				msg := &pcol.ResValSetRequest{
					Res: []*pcol.Res{},
				}
				resSet := &pcol.Res{
					Name:    r.GetName(),
					ResType: r.GetResType(),
				}
				fset(resSet, val)
				msg.Res = append(msg.Res, resSet)
				return SendProtoMsg(c.client, pcol.MessageType_RES_VAL_SET_REQUEST, msg)
			})
			c.resMap[r.GetName()] = r //addOrUpdateRes again data not changed
			return mgr.AddRes(s)
		} else {
			scalar := res.GetScalar[T](mgr, r.GetName())
			if scalar != nil {
				s, _ := scalar.(res.IScalarHelper[T])
				s.UpdateValue(val)
				c.resMap[r.GetName()].Reset()
				c.resMap[r.GetName()] = r
				return nil
			}
			if res, ok := c.resMap[r.GetName()]; ok {
				return fmt.Errorf("recv resource changed: %v - > %v", res, r)
			}
			s := res.NewScalar(r.GetName(), r.Description, val)
			c.resMap[r.GetName()] = r
			return mgr.AddRes(s)
		}
	}
}
